//===----------------------------------------------------------------------===//
//
//                         BusTub
//
// lru_replacer.cpp
//
// Identification: src/buffer/lru_replacer.cpp
//
// Copyright (c) 2015-2019, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "buffer/lru_replacer.h"
#include <algorithm>
#include <unordered_map>
#include <mutex>

namespace bustub {

LRUReplacer::LRUReplacer(size_t num_pages) {
 dummyHead = new ListNode(0);
 dummyTail = new ListNode(0);
 dummyHead->next = dummyTail;
 dummyTail->prev = dummyHead;
 this->capacity = num_pages;
 this->size = 0;
}

LRUReplacer::~LRUReplacer(){
  for(ListNode* cur=dummyHead;cur!=nullptr;cur=cur->next){
    ListNode* next=cur->next;
    delete(cur);
    cur = next;
  }
};
void LRUReplacer::moveToHead(ListNode *node){

}

void LRUReplacer::addToHead(ListNode *node){
  ListNode* second = dummyHead->next;
  dummyHead->next = node;
  node->next = second;
  second->prev = node;
  node->prev = dummyHead;
}
void LRUReplacer::removeNode(ListNode *node){
  ListNode* prev = node->prev;
  ListNode* next = node->next;
  prev->next = next;
  next->prev = prev;
  size--;
}
frame_id_t LRUReplacer::getTail(){
  return dummyTail->prev->frame_id;
}
void LRUReplacer::put(frame_id_t frame_id){
  if(cache.find(frame_id)== cache.end()){
    ListNode *node = new ListNode(frame_id);
    cache[frame_id] = node;
    addToHead(node);
    size++;
  }
}
void LRUReplacer::deleteFrame(frame_id_t frame_id){
  if(cache.find(frame_id)!=cache.end()){
  ListNode* toDel = cache[frame_id];
  this->removeNode(toDel);
  cache.erase(frame_id);
  }

}
bool LRUReplacer::Victim(frame_id_t *frame_id) {
  lru_latch.lock();
  frame_id_t f_id = getTail();
  if(f_id == -1){
    frame_id = nullptr;
    lru_latch.unlock();
    return false;
  }
  *frame_id =f_id;
  deleteFrame(f_id);
  lru_latch.unlock();
  return true;
}

void LRUReplacer::Pin(frame_id_t frame_id) {
  lru_latch.lock();
  deleteFrame(frame_id);
  lru_latch.unlock();
}

void LRUReplacer::Unpin(frame_id_t frame_id) {
  lru_latch.lock();
  put(frame_id);
  lru_latch.unlock();
}

size_t LRUReplacer::Size() { return this->size; }

}  // namespace bustub
